#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <assert.h>
#include <fcntl.h>
#define MAX 1024
#define ARGC 64

enum redi_type
{
    REDI_NONE,
    REDI_IN,
    REDI_OUT,
    REDI_APPEND
};

int main()
{
    //环境变量缓存区
    char myenviron[32][32] = {0};
    int row = 0;
    extern char** environ;
    
    int last_end_code = 0;


    while(1)
    {   
        enum redi_type rt = REDI_NONE;
        char file_name[64] = {0};

        printf("[ckf@VM-8-3-centos cur_file]$ ");
        //1.获取命令行指令字符串
        char cmdstr[MAX] = {0};
        fgets(cmdstr,sizeof(cmdstr)-1,stdin);
        cmdstr[strlen(cmdstr)-1] = '\0';//去掉'\n'
        //printf("%s\n",cmdstr);
        
        //判断是否为重定向命令
        int j = strlen(cmdstr)-1;
        while(j>=0)
        {
            if(cmdstr[j] == '<' || cmdstr[j] == '>')
            {

                if(cmdstr[j] == '<')
                {
                    //输入重定向
                    rt = REDI_IN;
                }
                else if(cmdstr[j] == '>')
                {
                    //追加重定向
                    if(cmdstr[j-1] == '>')
                    {
                        rt = REDI_APPEND;
                        cmdstr[j-1] = '\0';
                    }
                    //输出重定向
                    else
                    {
                        rt = REDI_OUT;
                    }
                }

                strcpy(file_name,&cmdstr[j+2]);
                cmdstr[j] = '\0';
                break;
            }
            
            j--;
        }
        //printf("%s\n",file_name);

        //2.分割cmdstr("ls -l -a" ==> "ls" "-l" "-a")
        char* argv[ARGC] = {NULL};
        argv[0] = strtok(cmdstr," ");
        //details
        int i = 1;
        if(strcmp(argv[0],"ls") == 0)
        {
            argv[i++] = "--color=auto";
        }
        while(argv[i++] = strtok(NULL," "));  
        
        //内建命令
        if(strcmp(argv[0],"cd") == 0)
        {
            if(argv[1])
            {
                chdir(argv[1]);
            }
            continue;
        }
        else if(strcmp(argv[0],"export") == 0)
        {
            if(argv[1])
            {
                char* cur = argv[1];
                int col = 0;
                while(*cur)
                {
                    myenviron[row][col++] = *(cur++);
                }
                putenv(myenviron[row]);
                row++;
            }
            continue;
        } 
        else if(strcmp(argv[0],"env") == 0)
        {
            int i=0;
            for(;environ[i];i++)
            {
                printf("[%d]%s\n",i,environ[i]);
            }
            continue;
        }
        else if(strcmp(argv[0],"echo") == 0)
        {
            if(argv[1])
            {
                if(argv[1][0]=='$')
                {
                    if(argv[1][1]=='?')
                    {
                        printf("%d\n",last_end_code);
                        continue;
                    }
                    printf("%s\n",getenv(argv[1]+1));
                }
            }
            continue;
        }
        
       // for(int i = 0;argv[i];i++)
       // {
       //     printf("argv[%d]:%s\n",i,argv[i]);
       // }
        
        //3.交给子进程运行
        pid_t id = fork();
        //子进程
        if(id == 0)
        {
            //判断是否是重定向
            if(rt != REDI_NONE)
            {
                umask(0);
                int fd = 0;
                switch(rt)
                {
                    case REDI_IN:
                        fd = open(file_name,O_RDONLY);
                        dup2(fd,0);
                        break;
                    case REDI_OUT:
                        fd = open(file_name,O_WRONLY|O_CREAT|O_TRUNC,0666);
                        dup2(fd,1);
                        break;
                    case REDI_APPEND:
                        fd = open(file_name,O_WRONLY|O_APPEND);
                        dup2(fd,1);
                        break;
                }

            }
            execvp(argv[0],argv);
            exit(1);//进程替换失败
        }
        //父进程
        int status = 0;
        waitpid(id,&status,0);
        last_end_code = WEXITSTATUS(status);
    }

    return 0;
}
